#pragma once

#include <memory>

namespace cpac
{
	namespace WarningTypes
	{
		enum 
		{
			WARNING_YPG =                1,
			WARNING_EVC = WARNING_YPG << 1,
		};
	}

	namespace details
	{
		template< class _WarningType >
		struct set_warning_type
		{
		};

		template< >
		struct set_warning_type< ypg_warning >
		{
			static const unsigned int _warning_type = WarningTypes::WARNING_YPG;
		};

		template< >
		struct set_warning_type< evc_warning >
		{
			static const unsigned int _warning_type = WarningTypes::WARNING_EVC;
		};

		struct ypg_warning{};
		struct evc_warning{};

		template< class _WarningType >
		struct warning_traits
		{
		};
	}

	class Warning
	{
	protected:
		struct WarningInterface;
		struct WarningObject;
		
		friend struct WarningInterface;
		friend struct WarningObject;

		std::shared_ptr< WarningInterface > _warning;

	public:
		template< class _WarningType >
		Warning(_WarningType const& in_warning_type)
			:_warning(new WarningObject< _WarningType >)
		{
		}

	protected:
		struct WarningInterface
		{
			virtual ~WarningInterface() {}

			template< class _WarningType >
		    virtual details::warning_traits< _WarningType > const& getInfo();
		};

		template< class _WarningType, typename _WarningTraits = details::warning_traits< _WarningType > >
		struct WarningObject
			: public WarningInterface
		{
			virtual ~WarningObject() {}

			virtual _WarningTraits const& getInfo() { return _warning_details; }

		protected:
			_WarningTraits _warning_details;
		};

	public:
		template< class _WarningType >
		warning_traits<_WarningType> const& getInfo()
		{
			return _warning->getInfo();
		}
	};

	namespace details
	{
		template< >
		struct warning_traits< ypg_warning >
		{
			const char* title;
		};

		template< >
		struct warning_traits< evc_warning >
		{
			const char* title;
		};
	}
}